﻿#region <!-- Using Directives -->

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Xml;

using WordSharpDev.Extensions;
using WordSharpDev.Properties;

using Word = Microsoft.Office.Interop.Word;

#endregion

namespace WordSharpDev.Work
{
	public class MetaProject
	{
		protected readonly FileInfo m_CurrentFile;

		protected readonly SqlConnection m_Connection;

		protected DirectoryInfo m_CurrentBuildDirectory;

		protected Boolean m_Saved;

		public MetaProject()
		{
			m_CurrentFile = Resources.GetDocument("MetaProject").AsFile();

			m_Connection = new SqlConnection(String.Format(@"Server=(localdb)\v11.0; Integrated Security=true; AttachDbFileName='{0}';", m_CurrentFile.FullName));
		}

		#region <!-- CountDocuments -->

		public Int32 CountDocuments()
		{
			try
			{
				m_Connection.Open();

				var l_Command = m_Connection.CreateCommand("EXEC [dbo].[CountDocuments]");

				var l_Result = Convert.ToInt32(l_Command.ExecuteScalar());

				return l_Result;
			}
			catch (Exception e)
			{
				throw new DataException("Could not count documents from app db", e);
			}
			finally
			{
				m_Connection.Close();
			}
		}

		#endregion

		#region <!-- ExistDocument -->

		public Boolean ExistDocument(String p_Key)
		{
			try
			{
				m_Connection.Open();

				var l_Command = m_Connection.CreateCommand("EXEC [dbo].[ExistDocument] @Key");

				l_Command.AddParamString(4000, "@Key", p_Key);

				return Convert.ToInt32(l_Command.ExecuteScalar()) == 1;
			}
			catch (Exception e)
			{
				throw new DataException("Could not determine whether a document exists", e);
			}
			finally
			{
				m_Connection.Close();
			}
		}

		#endregion

		#region <!-- GetDocuments -->

		public List<XmlNode> GetDocuments()
		{
			var l_Documents = new List<XmlNode>();

			try
			{
				m_Connection.Open();

				var l_Command = m_Connection.CreateCommand("EXEC [dbo].[GetDocuments]");

				using (var l_Reader = l_Command.ExecuteReader())
				{
					while (l_Reader.Read())
					{
						var l_Key = (String)l_Reader["Key"];

						var l_Node = l_Key.AsXmlNode();

						if (l_Node == null) continue;

						l_Documents.Add(l_Node);
					}
				}

				return l_Documents;
			}
			catch (Exception e)
			{
				throw new DataException("Could not get documents from app db", e);
			}
			finally
			{
				m_Connection.Close();
			}
		}

		#endregion

		#region <!-- SaveDocument -->

		public void SaveDocument(String p_Key, String p_FilePath)
		{
			try
			{
				m_Connection.Open();

				var l_Command = m_Connection.CreateCommand("EXEC [dbo].[SetDocument] @Key, @Data");

				l_Command.AddParamString(4000, "@Key", p_Key);

				l_Command.AddParamBinary("@Data", p_FilePath.ReadFile());

				l_Command.ExecuteNonQuery();
			}
			catch (Exception e)
			{
				throw new DataException("Could not merge document into app db", e);
			}
			finally
			{
				m_Connection.Close();				
			}
		}

		#endregion

		#region <!-- BuildDefault -->

		public void BuildDefault()
		{
			try
			{
				m_CurrentBuildDirectory = Root.GetTempSubDir(String.Format("Build {0:yyyy-MM-dd} {0:HH-mm-ss}", DateTime.Now), true);

				var l_Documents = ExtractDocuments(m_CurrentBuildDirectory.CreateSubdirectory("WordSharpDocs").FullName);

				var l_TargetDocument = Share.Application.Documents.Add(DocumentType: Word.WdNewDocumentType.wdNewBlankDocument, Visible: false);

				foreach (var i_Key in l_Documents.Keys)
				{
					var l_SourceDocument = Share.Application.Documents.Open(l_Documents[i_Key], ReadOnly: true, Visible: false);

					ExtractCode(l_SourceDocument, l_TargetDocument);

					((Word._Document)l_SourceDocument).Close();
				}

				l_TargetDocument.SaveAs(Path.Combine(m_CurrentBuildDirectory.FullName, String.Format("SourceCode.docx")));

				VisualBuilder.Build(l_TargetDocument);

				((Word._Document)l_TargetDocument).Close();
			}
			catch (Exception e)
			{
				throw new DataException("Could not build meta project", e);
			}
		}

		#endregion

		#region <!-- ExtractDocuments -->

		protected Dictionary<String, String> ExtractDocuments(String p_OutputDirectory)
		{
			var l_Documents = new Dictionary<String, String>();

			try
			{
				m_Connection.Open();

				var l_Index = 1;

				var l_Command = m_Connection.CreateCommand("SELECT [Key], [Data] FROM [Documents]");

				using (var l_Reader = l_Command.ExecuteReader())
				{
					while (l_Reader.Read())
					{
						var l_Key = (String)l_Reader["Key"];
						var l_Data = (Byte[])l_Reader["Data"];

						var l_File = Path.Combine(p_OutputDirectory, String.Format("Document_{0:000}.docx", l_Index++));

						using (var l_Stream = new FileStream(l_File, FileMode.Create))
						{
							l_Stream.Write(l_Data, 0, l_Data.Length);
							l_Stream.Flush();
						}

						l_Documents.Add(l_Key, l_File);
					}
				}

				return l_Documents;
			}
			catch (Exception e)
			{
				throw new DataException("Could not extract documents from app db", e);
			}
			finally
			{
				m_Connection.Close();
			}
		}

		#endregion

		#region <!-- ExtractCode -->

		protected void ExtractCode(Word.Document p_FromDocument, Word.Document p_ToDocument)
		{
			var l_Target = p_ToDocument.StoryRanges[Word.WdStoryType.wdMainTextStory];

			foreach (Word.Table i_Table in p_FromDocument.Tables)
			{
				var l_Node = i_Table.Descr.AsXmlNode();

				if (l_Node != null && l_Node.Name.IsLikeFull("Code"))
				{
					i_Table.Range.Copy();

					l_Target.Paragraphs.Add().Range.Paste();
				}
			}
		}

		#endregion
	}
}